Red Hat Enterprise Linux Implementation

Apache HTTPD Web Service

Module Topics

  • Apache HTTPD

  • Virtual Hosts

  • HTTPS

  • Dynamic Web Content

Apache HTTPD

Introduction to Apache HTTPD
  • Apache HTTPD is one of most-used web servers on Internet

  • Web server is daemon that speaks http(s)

    • Text-based protocol for sending and receiving objects over network connection

  • http is sent over wire in clear text, using port 80/TCP by default

    • 443/TCP also by default

  • Basic HTTP exchange has client connecting to server and using GET to request resource

    • Other commands, like HEAD and POST, allow clients to:

      • Request just resource metadata

      • Send server more information

Apache HTTPD

Example HTTP Request
GET /hello.html HTTP/1.1
Host: webapp0.example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0
Example HTTP Reply
  • Content-Type header is mandatory, telling client type of content being sent

  • Length of content must match length in Content-Length header

    HTTP/1.1 200 OK
    Date: Tue, 27 May 2014 09:57:40 GMT
    Server: Apache/2.4.6 (Red Hat) OpenSSL/1.0.1e-fips mod_wsgi/3.4 Python/2.7.5
    Content-Length: 12
    Keep-Alive: timeout=5, max=82
    Connection: Keep-Alive
    Content-Type: text/plain; charset=UTF-8
    
    Hello World!

Apache HTTPD

  • HTTP protocol seems easy, but difficult to implement with:

    • Security

    • Support for clients that do not adhere to standard

    • Support for dynamically generated pages

  • Most application developers do not write web servers

  • Instead, write applications to run behind web server like Apache HTTPD

Apache HTTPD

  • Fully configurable and extendable web server with full HTTP support

  • Can extend with modules

  • Provided in httpd package

  • web-server package group also installs httpd-manual package

Apache HTTPD

  • Red Hat Enterprise Linux 7 ships with web-server-environment environment group

  • web-server-environment pulls in web-server group by default

    • Includes optional groups for backup tools and database clients

  • Dependency of httpd is httpd-tools package

  • httpd-tools includes tools to:

    • Manipulate password maps and databases

    • Resolve IP addresses in logfiles to hostnames

    • Benchmark and stress-test web servers (ab)

Apache HTTPD

Configuring Apache HTTPD
  • After installation, default configuration written to /etc/httpd/conf/httpd.conf

  • Serves contents of /var/www/html for requests coming in to any hostname over plain HTTP

  • Basic syntax of httpd.conf is

    • Key Value configuration directives

    • HTML-like <Blockname parameter> blocks with embedded directives

  • Key/value pairs outside block affect entire server configuration

  • Key/value pairs inside block affect configuration indicated by block, or when requirement set by block is met

Apache HTTPD

ServerRoot "/etc/httpd" (1)
Listen 80 (2)
Include conf.modules.d/*.conf (3)
User apache (4)
Group apache (5)
ServerAdmin root@localhost (6)
<Directory /> (7)
    AllowOverride none
    Require all denied
</Directory>
DocumentRoot "/var/www/html" (8)
<Directory "/var/www">
    AllowOverride None
    Require all granted
</Directory>
<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>
<IfModule dir_module> (9)
    DirectoryIndex index.html
/</IfModule>
<Files ".ht*"> (10)
    Require all denied
</Files>
ErrorLog "logs/error_log" (11)
LogLevel warn
<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    <IfModule logio_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O"     combinedio
    </IfModule>
    CustomLog "logs/access_log" combined (12)
</IfModule>
AddDefaultCharset UTF-8 (13)
IncludeOptional conf.d/*.conf (14)

Apache HTTPD

Starting Apache HTTPD
  • Start httpd from the httpd.service systemd unit

    [root@server1 ~]# systemctl enable httpd.service
    [root@server1 ~]# systemctl start httpd.service
  • To request status information, use systemctl status -l httpd.service

    • If httpd fails to start, output typically indicates why

Apache HTTPD

Network Security
  • firewalld has two predefined services for httpd:

    • http opens port 80/TCP

    • https opens port 443/TCP

      [root@server1 ~]# firewall-cmd --permanent --add-service=http --add-service=https
      [root@server1 ~]# firewall-cmd --reload
  • In default configuration, SELinux allows httpd to bind to specific ports

  • To see list of ports, use semanage port -l | grep '^http_'

  • For overview of allowed port contexts and their usage, see httpd_selinux (8) man page from selinux-policy-devel package

Apache HTTPD

Using Alternate Document Root
  • Content does not need to be served out of /var/www/html

  • When changing DocumentRoot setting, make these changes also:

    • File system permissions: Any new DocumentRoot must be readable by apache user or apache group

      • In most cases, DocumentRoot should never be writable by apache user or group

    • SELinux: Default SELinux policy restricts what contexts can be read by httpd

      • Default context for web server content is httpd_sys_content_t

      • Rules are in place to relabel /srv/*/www/ with this context

  • To serve content from outside standard locations, use semanage to add new context rule

    [root@server1 ~]# semanage fcontext -a -t httpd_sys_content_t '/new/location(/.*)?'
Reference
  • httpd_selinux(8) man page from the selinux-policy-devel package

Apache HTTPD

Allowing Write Access to DocumentRoot
  • In default configuration, only root has write access to DocumentRoot

  • To provide write access to DocumentRoot:

    1. Set (default) ACL on DocumentRoot

      • Example: Give write access to webmasters group, and use /var/www/html as DocumentRoot

        [root@server1 ~]# setfacl -R -m g:webmasters:rwX /var/www/html
        [root@server1 ~]# setfacl -R -m d:g:webmasters:rwx /var/www/html
      • Uppercase X bit sets executable bit only on directories

        • Not directories and files

      • Especially relevant when done in conjunction with recursive action on directory tree

Apache HTTPD

  1. Create new DocumentRoot owned by webmasters group (sticky bit set)

    [root@server1 ~]# mkdir -p -m 2775 /new/docroot
    [root@server1 ~]# chgrp webmasters /new/docroot
  2. Combine first two approaches with other permissions closed off, and ACL added for apache group

References
  • httpd(8) and httpd_selinux(8) man pages

  • httpd-manual package contents

Virtual Hosts

Introduction
  • Virtual hosts allow single httpd server to serve content for multiple domains

  • httpd can use different settings, including DocumentRoot, based on:

    • IP address of server connected to

    • Hostname requested by client in HTTP request

    • Combination of both

  • Typically used when not cost-effective to spin up multiple VMs for many low-traffic sites

    • Example: Shared hosting environment

Virtual Hosts

Configuring Virtual Hosts
  • To configure virtual hosts, use <VirtualHost> blocks inside main configuration

  • To ease administration, virtual host blocks are not defined in /etc/httpd/conf/httpd.conf

    • Defined instead in separate .conf files in /etc/httpd/conf.d/

  • Example /etc/httpd/conf.d/site1.conf file

    <Directory /srv/site1/www> (1)
        Require all granted
        AllowOverride None
    </Directory>
    
    <VirtualHost 192.168.0.1:80> (2)
        DocumentRoot /srv/site1/www (3)
        ServerName site1.example.com (4)
        ServerAdmin webmaster@site1.example.com (5)
        ErrorLog "logs/site1_error_log" (6)
        CustomLog "logs/site1_access_log" combined (7)
    </VirtualHost>

Virtual Hosts

Name-Based vs. IP-Based Virtual Hosting
  • Every virtual host is IP-based: sorts traffic to virtual hosts based on IP address client connected to

  • If multiple virtual hosts are declared for single IP/port combination, ServerName and ServerAlias directives are consulted

    • This effectively enables name-based virtual hosting

Wildcards and Priority
  • IP address part of <VirtualHost> directive can be replaced with wildcards _default_ and *

    • Both mean "match anything"

  • When HTTP request comes in:

    • httpd first tries to match against virtual hosts with explicit IP address

    • If no match, checks virtual hosts with wildcard IP address

    • If no match, main server configuration is used

Virtual Hosts

<VirtualHost *:80>
  • <VirtualHost *:80> always matches regular HTTP traffic on port 80/TCP

    • Effectively disables main server configuration for traffic on port 80/TCP

  • If no match found for ServerName or ServerAlias, and multiple virtual hosts are defined for IP/port combination request came in on, first virtual host that matches IP/port is used

    • "First" determined by order in which hosts are defined in configuration file

    • Multiple *.conf files are included in alphanumeric order

      • To create catch-all (default) virtual host, name configuration file something like 00-default.conf

Virtual Hosts

Troubleshooting Virtual Hosts
  • Configure separate DocumentRoot for each virtual host, with identifying content

  • Configure separate log files for error logging and access logging

  • Evaluate order in which virtual host definitions are parsed by httpd

    • Files are read in alphanumeric order based on filename

  • Disable virtual hosts one by one to isolate a problem

    • Comment out virtual host definitions in configuration file(s)

    • Temporarily rename include files to not end in .conf

  • Use journalctl UNIT=httpd.service to isolate log messages from just httpd.service

References
  • httpd(8) man page

  • httpd-manual package contents

HTTPS

Transport Layer Security (TLS)
  • TLS used to encrypt network communications

    • Successor to Secure Sockets Layer (SSL)

  • Allows client to verify identity of server, and server to verify client

  • Based on certificates

  • Certificate has multiple parts:

    • Public key

    • Server identity

    • Signature from certificate authority

  • Corresponding private key is never made public

    • Any data encrypted with private key can be decrypted only with public key, and vice versa

HTTPS

TLS Handshake
  • During initial handshake:

    • Set up encrypted connection

    • Client and server agree on set of encryption ciphers supported by both

    • Client and server exchange bits of random data

  • Client uses random data to generate session key

    • Key used for faster symmetric encryption—same key used for both encryption and decryption

  • To secure key, it is sent to server encrypted with server’s public key (part of server certificate)

HTTPS

TLS handshake

HTTPS

Configuring TLS certificates
  • Obtain signed certificate

  • Install Apache HTTPD extension modules to support TLS

  • Configure virtual TLS host

Obtaining a Certificate
  • Two options:

    • Create self-signed certificate (signed by itself, not Certificate Authority)

    • Create certificate request

      • Have reputable CA sign request so it becomes a certificate

  • crypto-utils package contains genkey utility that supports both methods

HTTPS

  • To create certificate (signing request) with genkey:

    [root@server1 ~]# genkey <FQDN>
    • <FQDN> is fully qualified domain name clients use to connect to server

  • genkey asks following:

    • Desired key size: Choose at least 2048 bits

    • Should signing request be made: Answering no creates self-signed certificate

    • Should private key be protected with passphrase

    • Identity of server

HTTPS

  • After certificate process completes, several files are created:

    • /etc/pki/tls/private/<fqdn>.key: Private key

      • Keep at 0600 or 0400 permissions

      • SELinux context of cert_t

      • Do not share

    • /etc/pki/tls/certs/<fqdn>.0.csr: Generated if signing request created

      • Send to CA to be signed

      • Never need to send private key to CA

    • /etc/pki/tls/certs/<fqdn>.crt: Public certificate

      • Returned from the CA when self-signed certificate requested

      • Keep permissions at 0644 with SELinux context of cert_t

HTTPS

Installing Apache HTTPD Modules
  • Apache HTTPD needs extension module to activate TLS support

    • Install using mod_ssl package

  • mod_ssl enables httpd for default virtual host listening on port 443/TCP

    • Host configured in /etc/httpd/conf.d/ssl.conf

Configuring Virtual Host with TLS
  • Configure TLS virtual hosts same as regular virtual hosts with additional parameters

  • Can use name-based virtual hosting with TLS, but some older browsers are not compatible

HTTPS

Simplified /etc/httpd/conf.d/ssl.conf
Listen 443 https (1)
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog (2)
SSLSessionCache         shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout  300
SSLRandomSeed startup file:/dev/urandom  256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
<VirtualHost _default_:443> (3)
    ErrorLog logs/ssl_error_log
    TransferLog logs/ssl_access_log
    LogLevel warn
    SSLEngine on (4)
    SSLProtocol all -SSLv2 (5)
    SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5 (6)
    SSLCertificateFile /etc/pki/tls/certs/localhost.crt (7)
    SSLCertificateKeyFile /etc/pki/tls/private/localhost.key(8)
    CustomLog logs/ssl_request_log \
            "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

HTTPS

  • If signed certificate used, and certificate does not have embedded copies of all certificates used in signing up to root CA, server must provide certificate chain

    • Copy of all CA certificates used in signing process concatenated together

    • To identify file, use SSLCertificateChainFile directive

  • When defining new TLS-encrypted virtual host, do not need to copy entire contents of ssl.conf

    • Need <VirtualHost> block with SSLEngine On directive

    • Need configuration for certificates

HTTPS

  • Example of name-based TLS virtual host

    <VirtualHost *:443>
      ServerName demo.example.com
      SSLEngine on
      SSLCertificateFile /etc/pki/tls/certs/demo.example.com.crt
      SSLCertificateKeyFile /etc/pki/tls/private/demo.example.com.key
      SSLCertificateChainFile /etc/pki/tls/certs/example-ca.crt
    </VirtualHost>
  • Example is missing important directives such as DocumentRoot

    • Are inherited from main configuration

Not defining protocols and ciphers to use results in httpd using default options. httpd defaults are not considered secure. It is highly recommended to restrict both to a more secure subset.

HTTPS

Configuring Forward Secrecy
  • If server private key is compromised (server break-in, crypto code bug), attacker could decrypt recorded session

  • Protecting against these types of attacks is called ensuring forward secrecy

  • To establish forward secrecy:

    • Carefully tune allowed ciphers in SSLCipherSuite directive

    • Have server always select most preferred cipher that both server and client support

HTTPS

  • Example: Best set of ciphers to allow

    SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
    SSLHonorCipherOrder On
    • List prioritizes ciphers that perform initial session key exchange using elliptic curve Diffie-Hellman (EECDH) algorithms

    • Session key is never transmitted; it is calculated by both sides

    • SSLHonorCipherOrder On directive (last line) instructs httpd to prefer ciphers listed earlier in SSLCipherSuite list, regardless of client preference

  • Security research is always-ongoing

    • Re-evaluate selected ciphers on regular basis

HTTPS

Configuring HTTP Strict Transport Security (HSTS)
  • Common misconfiguration, which results in warnings in most browsers, is having web page served out over HTTPS include resources served out over clear-text HTTP

  • To protect against this, add line inside <VirtualHost> block that has TLS enabled

    Header always set Strict-Transport-Security "max-age=15768000"
    • Sending extra header informs clients they are not allowed to fetch resources for this page that are not served using TLS

  • Another issue is clients connecting over HTTP to resource they should have used HTTPS for

  • Not serving content over HTTP solves issue

    • More subtle approach is to redirect clients connecting over HTTP to the same resource using HTTPS

HTTPS

  • To set up redirect, configure http virtual host for same ServerName and ServerAlias as TLS-protected virtual host

    • Catch-all virtual host can be used

  • Add following lines inside <VirtualHost *:80> block:

    RewriteEngine on
    RewriteRule ^(/.*)$ https://%{HTTP_POST}$1 [redirect=301]
    • RewriteEngine on directive turns on URL rewrite module for virtual host

    • RewriteRule matches any resource (^(/.*)$) and redirects it using HTTP Moved Permanently message ([redirect=301]) to same resource served out over HTTPS

    • %{HTTP_HOST} variable uses hostname requested by client, while $1 part is back-reference to whatever was matched between first set of parentheses in regular expression

References

Dynamic Web Content

Common Gateway Interface (CGI)
  • CGI is one of oldest forms of generating dynamic content

  • When CGI resource is requested, httpd executes resource as process and serves the stdout of that process

  • CGI resources mostly written in scripting languages like Perl

    • C programs and Java executables also common

  • Environment variables used to make request information (including client info) available to CGI program

Dynamic Web Content

Configuring httpd for CGI
  • To have httpd treat location as CGI executables, use following syntax in httpd configuration

    ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
  • Instructs httpd to redirect requests for files under /cgi-bin/ URI to /var/www/cgi-bin/ directory and treat files in that directory as executable scripts

  • CGI scripts:

    • Are executed as apache user and group

    • Should be executable by apache user and group

    • Should have httpd_sys_script_exec_t SELinux context

  • CGI directory:

    • Should have Options None

    • Should have access granted using normal <Directory> block

Dynamic Web Content

Serving Dynamic PHP Content
  • PHP scripting language is popular way to provide dynamic content

  • Performance and security improved by having httpd run PHP interpreter internally

  • php package adds special mod_php module httpd

  • Default configuration for mod_php adds lines to httpd

    <FilesMatch \.php$>
      SetHandler application/x-httpd-php
    <FilesMatch>
    DirectoryIndex index.php
    • <FilesMatch> block instructs httpd to use mod_php for file names ending in .php

    • DirectoryIndex directive adds index.php to list of files searched when directory is requested

Dynamic Web Content

Serving Dynamic Python Content
  • Python scripts also popular for dynamic content

  • python and httpd support newer Web Server Gateway Interface (WSGI) protocol

  • mod_wsgi package adds WSGI support to httpd

  • Unlike mod_php or CGI, WSGI does not start new script/interpreter for every request

    • Main application is started, and all requests are routed to that application

  • To configure httpd to support WSGI application:

    • Install mod_wsgi package

    • Add WSGIScriptAlias line to virtual host definition

Dynamic Web Content

  • Example: Send all requests for http://servername/myapp and any resources below it to WSGI application /srv/myapp/www/myapp.py

    WSGIScriptAlias /myapp/ /srv/myapp/www/myapp.py
  • WSGI applications should:

    • Be executable by apache user and group

    • Have SELinux contexts set to httpd_sys_content_t

Dynamic Web Content

Database Connectivity
  • Most web applications store and retrieve persistent data

    • Common approach is database such as MariaDB or PostgreSQL

  • When database runs on same host as web server and uses standard network port, SELinux allows network connection from web application

  • When database runs on remote host, set SELinux Boolean httpd_can_network_connect_db to 1 to allow connection

  • When network connection needed from within web application, and target is not well-known database port, set SELinux Boolean httpd_can_network_connect to 1 to allow connection

  • Other SELinux Booleans also affect how web applications are executed by httpd

References
  • httpd(8) and httpd_php_selinux(8) man pages

  • httpd-manual package contents

  • /usr/share/doc/mod_wsgi-*/README

Summary

  • Apache HTTPD

  • Virtual Hosts

  • HTTPS

  • Dynamic Web Content

Module Completion

Nice job!

Click the button below to complete this module of the course: